home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / C++ / Direct3D / MultiAnimation / MultiAnimationLib.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-27  |  15.9 KB  |  529 lines

  1. //-----------------------------------------------------------------------------
  2. // File: MultiAnimationLib.cpp
  3. //
  4. // Desc: Implementation of the CMultiAnim class. This class manages the animation
  5. //       data (frames and meshes) obtained from a single X file.
  6. //
  7. // Copyright (c) Microsoft Corporation. All rights reserved
  8. //-----------------------------------------------------------------------------
  9. #include "dxstdafx.h"
  10. #include "MultiAnimation.h"
  11.  
  12. using namespace std;
  13.  
  14.  
  15. //-----------------------------------------------------------------------------
  16. // Name: MultiAnimMC::SetupBonePtrs()
  17. // Desc: Initialize the m_apmxBonePointers member to point to the bone matrices
  18. //       so that we can access the bones by index easily.  Called from
  19. //       CMultiAnim::SetupBonePtrs().
  20. //-----------------------------------------------------------------------------
  21. HRESULT MultiAnimMC::SetupBonePtrs( D3DXFRAME * pFrameRoot )
  22. {
  23.     if( pSkinInfo )
  24.     {
  25.         if( m_apmxBonePointers )
  26.             delete [] m_apmxBonePointers;
  27.  
  28.         DWORD dwNumBones = pSkinInfo->GetNumBones();
  29.  
  30.         m_apmxBonePointers = new D3DXMATRIX* [ dwNumBones ];
  31.         if( m_apmxBonePointers == NULL )
  32.             return E_OUTOFMEMORY;
  33.  
  34.         for( DWORD i = 0; i < dwNumBones; ++ i )
  35.         {
  36.             MultiAnimFrame *pFrame = (MultiAnimFrame *) D3DXFrameFind( pFrameRoot, pSkinInfo->GetBoneName( i ) );
  37.             if( pFrame == NULL )
  38.                 return E_FAIL;
  39.  
  40.             m_apmxBonePointers[ i ] = &pFrame->TransformationMatrix;
  41.         }
  42.     }
  43.  
  44.     return S_OK;
  45. }
  46.  
  47.  
  48.  
  49.  
  50. //-----------------------------------------------------------------------------
  51. // Name: CMultiAnim::CreateInstance()
  52. // Desc: Create a new animation instance based on our animation frames and
  53. //       animation controller.
  54. //-----------------------------------------------------------------------------
  55. HRESULT CMultiAnim::CreateInstance( CAnimInstance ** ppAnimInstance )
  56. {
  57.     * ppAnimInstance = NULL;
  58.  
  59.     LPD3DXANIMATIONCONTROLLER pNewAC = NULL;
  60.     HRESULT hr;
  61.     CAnimInstance * pAI = NULL;
  62.  
  63.     // Clone the original AC.  This clone is what we will use to animate
  64.     // this mesh; the original never gets used except to clone, since we
  65.     // always need to be able to add another instance at any time.
  66.     hr = m_pAC->CloneAnimationController( m_pAC->GetMaxNumAnimationOutputs(),
  67.                                           m_pAC->GetMaxNumAnimationSets(),
  68.                                           m_pAC->GetMaxNumTracks(),
  69.                                           m_pAC->GetMaxNumEvents(),
  70.                                           &pNewAC );
  71.     if( SUCCEEDED( hr ) )
  72.     {
  73.         // create the new AI
  74.         pAI = new CAnimInstance( this );
  75.         if( pAI == NULL )
  76.         {
  77.             hr = E_OUTOFMEMORY;
  78.             goto e_Exit;
  79.         }
  80.  
  81.         // set it up
  82.         hr = pAI->Setup( pNewAC );
  83.         if( FAILED( hr ) )
  84.             goto e_Exit;
  85.  
  86.         * ppAnimInstance = pAI;
  87.     }
  88.  
  89. e_Exit:
  90.  
  91.     if( FAILED( hr ) )
  92.     {
  93.         if( pAI )
  94.             delete pAI;
  95.  
  96.         if( pNewAC )
  97.             pNewAC->Release();
  98.     }
  99.  
  100.     return hr;
  101. }
  102.  
  103.  
  104.  
  105.  
  106. //-----------------------------------------------------------------------------
  107. // Name: CMultiAnim::SetupBonePtrs()
  108. // Desc: Recursively initialize the bone pointers for all the mesh
  109. //       containers in the hierarchy.
  110. //-----------------------------------------------------------------------------
  111. HRESULT CMultiAnim::SetupBonePtrs( MultiAnimFrame * pFrame )
  112. {
  113.     assert( pFrame != NULL );
  114.  
  115.     HRESULT hr;
  116.  
  117.     if( pFrame->pMeshContainer )
  118.     {
  119.         // call setup routine
  120.         hr = ( (MultiAnimMC *) pFrame->pMeshContainer )->SetupBonePtrs( m_pFrameRoot );
  121.         if(FAILED( hr ) )
  122.             return hr;
  123.     }
  124.     
  125.     if( pFrame->pFrameSibling )
  126.     {
  127.         // recursive call
  128.         hr = SetupBonePtrs( (MultiAnimFrame *) pFrame->pFrameSibling );
  129.         if(FAILED( hr ) )
  130.             return hr;
  131.     }
  132.     
  133.     if( pFrame->pFrameFirstChild )
  134.     {
  135.         // recursive call
  136.         hr = SetupBonePtrs( (MultiAnimFrame *) pFrame->pFrameFirstChild );
  137.         if(FAILED( hr ) )
  138.             return hr;
  139.     }
  140.  
  141.     return S_OK;
  142. }
  143.  
  144. CMultiAnim::CMultiAnim() :
  145.     m_pDevice( NULL ),
  146.     m_pEffect( NULL ),
  147.     m_dwWorkingPaletteSize( 0 ),
  148.     m_amxWorkingPalette( NULL ),
  149.     m_pFrameRoot( NULL ),
  150.     m_pAC( NULL )
  151. {
  152. }
  153.  
  154.  
  155.  
  156.  
  157. //-----------------------------------------------------------------------------
  158. // Name: CMultiAnim::~CMultiAnim()
  159. // Desc: Destructor for CMultiAnim
  160. //-----------------------------------------------------------------------------
  161. CMultiAnim::~CMultiAnim()
  162. {
  163.     vector< CAnimInstance* >::iterator itCur, itEnd = m_v_pAnimInstances.end();
  164.     for( itCur = m_v_pAnimInstances.begin(); itCur != itEnd; ++ itCur )
  165.     {
  166.         ( * itCur )->Cleanup();
  167.         delete * itCur;
  168.     }
  169.  
  170.     m_v_pAnimInstances.clear();
  171. }
  172.  
  173.  
  174.  
  175. //-----------------------------------------------------------------------------
  176. // Name: CMultiAnim::Setup()
  177. // Desc: The class is initialized with this method.
  178. //       We create the effect from the fx file, and load the animation mesh
  179. //       from the given X file.  We then call SetupBonePtrs() to initialize
  180. //       the mesh containers to enable bone matrix lookup by index.  The
  181. //       Allocation Hierarchy is passed by pointer to allow an app to subclass
  182. //       it for its own implementation.
  183. //-----------------------------------------------------------------------------
  184. HRESULT CMultiAnim::Setup( LPDIRECT3DDEVICE9 pDevice,
  185.                            WCHAR sXFile[],
  186.                            WCHAR sFxFile[],
  187.                            CMultiAnimAllocateHierarchy *pAH,
  188.                            LPD3DXLOADUSERDATA pLUD )
  189. {
  190.     assert( pDevice != NULL );
  191.     assert( sXFile );
  192.     assert( sFxFile );
  193.     assert( pAH );
  194.  
  195.     // set the MA instance for CMultiAnimAllocateHierarchy
  196.     pAH->SetMA( this );
  197.  
  198.     // set the device
  199.     m_pDevice = pDevice;
  200.     m_pDevice->AddRef();
  201.  
  202.     HRESULT hr;
  203.     D3DXVECTOR3 vCenter;
  204.     LPD3DXEFFECTCOMPILER pEC = NULL;
  205.  
  206.     // Increase the palette size if the shader allows it. We are sort
  207.     // of cheating here since we know tiny has 35 bones. The alternative
  208.     // is use the maximum number that vs_2_0 allows.
  209.     D3DXMACRO mac[2] =
  210.     {
  211.         { "MATRIX_PALETTE_SIZE_DEFAULT", "35" },
  212.         { NULL,                          NULL }
  213.     };
  214.  
  215.     // If we support VS_2_0, increase the palette size; else, use the default
  216.     // of 26 bones from the .fx file by passing NULL
  217.     D3DCAPS9 caps;
  218.     D3DXMACRO *pmac = NULL;
  219.     m_pDevice->GetDeviceCaps( & caps );
  220.     if( caps.VertexShaderVersion > D3DVS_VERSION( 1, 1 ) )
  221.         pmac = mac;
  222.  
  223.     // create effect -- do this first, so LMHFX has access to the palette size
  224.     WCHAR wszPath[ MAX_PATH ];
  225.     hr = DXUTFindDXSDKMediaFileCch( wszPath, MAX_PATH, sFxFile );
  226.     if( FAILED( hr ) )
  227.         goto e_Exit;
  228.  
  229.     // Define DEBUG_VS and/or DEBUG_PS to debug vertex and/or pixel shaders with the shader debugger.  
  230.     // Debugging vertex shaders requires either REF or software vertex processing, and debugging 
  231.     // pixel shaders requires REF.  The D3DXSHADER_FORCE_*_SOFTWARE_NOOPT flag improves the debug 
  232.     // experience in the shader debugger.  It enables source level debugging, prevents instruction 
  233.     // reordering, prevents dead code elimination, and forces the compiler to compile against the next 
  234.     // higher available software target, which ensures that the unoptimized shaders do not exceed 
  235.     // the shader model limitations.  Setting these flags will cause slower rendering since the shaders 
  236.     // will be unoptimized and forced into software.  See the DirectX documentation for more information 
  237.     // about using the shader debugger.
  238.     {
  239.         DWORD dwShaderFlags = 0;
  240.         #ifdef DEBUG_VS
  241.             dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT;
  242.         #endif
  243.         #ifdef DEBUG_PS
  244.             dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT;
  245.         #endif
  246.  
  247.         hr = D3DXCreateEffectFromFile( m_pDevice,
  248.                                        wszPath,
  249.                                        pmac,
  250.                                        NULL,
  251.                                        dwShaderFlags,
  252.                                        NULL,
  253.                                        &m_pEffect,
  254.                                        NULL );
  255.  
  256.         if( FAILED( hr ) )
  257.             goto e_Exit;
  258.     }
  259.  
  260.     // create the mesh, frame hierarchy, and animation controller from the x file
  261.     hr = DXUTFindDXSDKMediaFileCch( wszPath, MAX_PATH, sXFile );
  262.     if( FAILED( hr ) )
  263.         goto e_Exit;
  264.  
  265.     hr = D3DXLoadMeshHierarchyFromX( wszPath,
  266.                                      0,
  267.                                      m_pDevice,
  268.                                      pAH,
  269.                                      pLUD,
  270.                                      (LPD3DXFRAME *) &m_pFrameRoot,
  271.                                      &m_pAC );
  272.     if( FAILED( hr ) )
  273.         goto e_Exit;
  274.  
  275.     if( !m_pAC )
  276.     {
  277.         hr = E_FAIL;
  278.         MessageBox( NULL,
  279.                     L"The sample is attempting to load a mesh without animation or incompatible animation.  This sample requires tiny_4anim.x or a mesh with identical animation sets.  The program will now exit.",
  280.                     L"Mesh Load Error", MB_OK );
  281.         goto e_Exit;
  282.     }
  283.  
  284.     // set up bone pointers
  285.     hr = SetupBonePtrs( m_pFrameRoot );
  286.     if( FAILED( hr ) )
  287.         goto e_Exit;
  288.  
  289.     // get bounding radius
  290.     hr = D3DXFrameCalculateBoundingSphere( m_pFrameRoot, & vCenter, & m_fBoundingRadius );
  291.     if( FAILED( hr ) )
  292.         goto e_Exit;
  293.  
  294.     // If there are existing instances, update their animation controllers.
  295.     {
  296.         vector< CAnimInstance* >::iterator itCur, itEnd = m_v_pAnimInstances.end();
  297.         for( itCur = m_v_pAnimInstances.begin(); itCur != itEnd; ++ itCur )
  298.         {
  299.             LPD3DXANIMATIONCONTROLLER pNewAC = NULL;
  300.             hr = m_pAC->CloneAnimationController( m_pAC->GetMaxNumAnimationOutputs(),
  301.                                                   m_pAC->GetMaxNumAnimationSets(),
  302.                                                   m_pAC->GetMaxNumTracks(),
  303.                                                   m_pAC->GetMaxNumEvents(),
  304.                                                   &pNewAC );
  305.             // Release existing animation controller
  306.             if( ( * itCur )->m_pAC )
  307.                 ( * itCur )->m_pAC->Release();
  308.             ( * itCur )->Setup( pNewAC );
  309.         }
  310.     }
  311.  
  312.  
  313. e_Exit:
  314.  
  315.     if( FAILED( hr ) )
  316.     {
  317.         if( m_amxWorkingPalette )
  318.         {
  319.             delete [] m_amxWorkingPalette;
  320.             m_amxWorkingPalette = NULL;
  321.             m_dwWorkingPaletteSize = 0;
  322.         }
  323.  
  324.         if( m_pAC )
  325.         {
  326.             m_pAC->Release();
  327.             m_pAC = NULL;
  328.         }
  329.  
  330.         if( m_pFrameRoot )
  331.         {
  332.             D3DXFrameDestroy( m_pFrameRoot, pAH );
  333.             m_pFrameRoot = NULL;
  334.         }
  335.  
  336.         if( m_pEffect )
  337.         {
  338.             m_pEffect->Release();
  339.             m_pEffect = NULL;
  340.         }
  341.  
  342.         if( pEC )
  343.             pEC->Release();
  344.  
  345.         m_pDevice->Release();
  346.         m_pDevice = NULL;
  347.     }
  348.  
  349.     return hr;
  350. }
  351.  
  352.  
  353.  
  354. //-----------------------------------------------------------------------------
  355. // Name: CMultiAnim::Cleanup()
  356. // Desc: Performs clean up work and free up memory.
  357. //-----------------------------------------------------------------------------
  358. HRESULT CMultiAnim::Cleanup( CMultiAnimAllocateHierarchy * pAH )
  359. {
  360.     if( m_amxWorkingPalette )
  361.     {
  362.         delete [] m_amxWorkingPalette;
  363.         m_amxWorkingPalette = NULL;
  364.         m_dwWorkingPaletteSize = 0;
  365.     }
  366.  
  367.     if( m_pAC )
  368.     {
  369.         m_pAC->Release();
  370.         m_pAC = NULL;
  371.     }
  372.  
  373.     if( m_pFrameRoot )
  374.     {
  375.         D3DXFrameDestroy( m_pFrameRoot, pAH );
  376.         m_pFrameRoot = NULL;
  377.     }
  378.  
  379.     if( m_pEffect )
  380.     {
  381.         m_pEffect->Release();
  382.         m_pEffect = NULL;
  383.     }
  384.  
  385.     if( m_pDevice )
  386.     {
  387.         m_pDevice->Release();
  388.         m_pDevice = NULL;
  389.     }
  390.  
  391.     return S_OK;
  392. }
  393.  
  394.  
  395.  
  396.  
  397. //-----------------------------------------------------------------------------
  398. // Name: CMultiAnim::GetDevice()
  399. // Desc: Returns the D3D device we work with.  The caller must call Release()
  400. //       on the pointer when done with it.
  401. //-----------------------------------------------------------------------------
  402. LPDIRECT3DDEVICE9 CMultiAnim::GetDevice()
  403. {
  404.     m_pDevice->AddRef();
  405.     return m_pDevice;
  406. }
  407.  
  408.  
  409.  
  410.  
  411. //-----------------------------------------------------------------------------
  412. // Name: CMultiAnim::GetEffect()
  413. // Desc: Returns the D3D effect object that the mesh is rendered with.  The
  414. //       caller must call Release() when done.
  415. //-----------------------------------------------------------------------------
  416. LPD3DXEFFECT CMultiAnim::GetEffect()
  417. {
  418.     if( m_pEffect )
  419.         m_pEffect->AddRef();
  420.  
  421.     return m_pEffect;
  422. }
  423.  
  424.  
  425.  
  426.  
  427. //-----------------------------------------------------------------------------
  428. // Name: CMultiAnim::GetNumInstance()
  429. // Desc: Returns the number of animation instances using our animation frames.
  430. //-----------------------------------------------------------------------------
  431. DWORD CMultiAnim::GetNumInstances()
  432. {
  433.     return (DWORD) m_v_pAnimInstances.size();
  434. }
  435.  
  436.  
  437.  
  438.  
  439. //-----------------------------------------------------------------------------
  440. // Name: CMultiAnim::GetInstance()
  441. // Desc: Returns a CAnimInstance object by index.
  442. //-----------------------------------------------------------------------------
  443. CAnimInstance * CMultiAnim::GetInstance( DWORD dwIndex )
  444. {
  445.     assert( dwIndex < m_v_pAnimInstances.size() );
  446.     return m_v_pAnimInstances[ dwIndex ];
  447. }
  448.  
  449.  
  450.  
  451.  
  452. //-----------------------------------------------------------------------------
  453. // Name: CMultiAnim::GetBoundingRadius()
  454. // Desc: Returns the bounding radius for the mesh object.
  455. //-----------------------------------------------------------------------------
  456. float CMultiAnim::GetBoundingRadius()
  457. {
  458.     return m_fBoundingRadius;
  459. }
  460.  
  461.  
  462.  
  463.  
  464. //-----------------------------------------------------------------------------
  465. // Name: CMultiAnim::CreateNewInstance()
  466. // Desc: Creates a new animation instance and adds it to our instance array.
  467. //       Then returns the index of the newly created instance.
  468. //-----------------------------------------------------------------------------
  469. HRESULT CMultiAnim::CreateNewInstance( DWORD * pdwNewIdx )
  470. {
  471.     // create the AI
  472.     CAnimInstance * pAI;
  473.     HRESULT hr = CreateInstance( & pAI );
  474.     if( FAILED( hr ) )
  475.         goto e_Exit;
  476.  
  477.     // add it
  478.     try
  479.     {
  480.         m_v_pAnimInstances.push_back( pAI );
  481.     }
  482.     catch( ... )
  483.     {
  484.         hr = E_OUTOFMEMORY;
  485.         goto e_Exit;
  486.     }
  487.  
  488.     * pdwNewIdx = (DWORD) m_v_pAnimInstances.size() - 1;
  489.  
  490. e_Exit:
  491.  
  492.     return hr;
  493. }
  494.  
  495.  
  496.  
  497.  
  498. //-----------------------------------------------------------------------------
  499. // Name: CMultiAnim::SetTechnique()
  500. // Desc: Sets the name of the technique to render the mesh in.
  501. //-----------------------------------------------------------------------------
  502. void CMultiAnim::SetTechnique( char * sTechnique )
  503. {
  504.     m_sTechnique = sTechnique;
  505. }
  506.  
  507.  
  508.  
  509.  
  510. //-----------------------------------------------------------------------------
  511. // Name: CMultiAnim::Draw()
  512. // Desc: Render all animtion instances using our mesh frames.
  513. //-----------------------------------------------------------------------------
  514. HRESULT CMultiAnim::Draw()
  515. {
  516.     // TODO: modify this for much faster bulk rendering
  517.  
  518.     HRESULT hr = S_OK, hrT;
  519.  
  520.     vector< CAnimInstance* >::iterator itCur, itEnd = m_v_pAnimInstances.end();
  521.     for( itCur = m_v_pAnimInstances.begin(); itCur != itEnd; ++ itCur )
  522.     {
  523.         if( FAILED( hrT = ( * itCur )->Draw() ) )
  524.             hr = hrT;
  525.     }
  526.  
  527.     return hr;
  528. }
  529.